// ==================================================================================
// Shared Genomics Project MPI Codebase
// Version 1.0 30/04/2010
//
// (c) 2010 University of Manchester all rights reserved
//
// This file is distributed under the GNU General Public License, Version 2.  
// Please see the file COPYING.txt for more details
// ==================================================================================

/*!
\file
\brief Implementation of Sample Person and Individual-Major Allelic Data
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "individual.h"

int individual_init(struct individual *p) {
	if (p != NULL) {
		p->fid = '\0';
		p->iid = '\0';
		p->pat = '\0';
		p->mat = '\0';
		p->pp = NULL;
		p->pm = NULL;
		p->pperson = NULL;
		p->sex = FALSE;
		p->phenotype = -9;
		p->sexcode = '\0';
		p->aff = FALSE;
		p->missing = FALSE;
		p->one = NULL;
		p->nOne = 0;
		p->two = NULL;
		p->nTwo = 0;
		p->sol = 0;
		p->founder = TRUE;
		p->pperson = p;
		
		return 1;
	}

	return 0;
}

struct individual* individual_create() {
	struct individual *p = NULL;

	p = (struct individual*) malloc(sizeof(struct individual));
	if (p != NULL) individual_init(p);
	
	return p;
}

int individual_free_attributes(struct individual *person) {
	if (person != NULL) {
		// Free FID code.
		if (person->fid != NULL) {
			free(person->fid);
			person->fid = NULL;
		}

		// Free IID code
		if (person->iid != NULL) {
			free(person->iid);
			person->iid = NULL;
		}

		// Free Mat value
		if (person->mat != NULL) {
			free(person->mat);
			person->mat = NULL;
		}

		// Free Pat value
		if (person->pat != NULL) {
			free(person->pat);
			person->pat = NULL;
		}

		// Set other person pointers to NULL.
		person->pp = NULL;
		person->pm = NULL;
		person->pperson = NULL;

		// Delete the SEX code string
		if (person->sexcode != NULL) {
			free(person->sexcode);
			person->sexcode =NULL;
		}

		// Alloc one/two BOOL arrays.
		if (person->one != NULL) {
			free(person->one);
			person->one = NULL;
			person->nOne = 0;
		}
		if (person->two != NULL) {
			free(person->two);
			person->two = NULL;
			person->nTwo = 0;
		}
	}

	return 0;
}

int individual_set_fid(struct individual *p, const char *value) {
	if (p != NULL && value != NULL) {
		if (p->fid != NULL) {
			free(p->fid);
			p->fid = NULL;
		}
		
		p->fid = (char*) malloc(strlen(value) + 1);
		if (p->fid != NULL) {
			strcpy(p->fid, value);
			return 1;
		}
	}

	return 0;
}

int individual_set_iid(struct individual *p, const char *value) {
	if (p != NULL && value != NULL) {
		if (p->iid != NULL) {
			free(p->iid);
			p->fid = NULL;
		}
		
		p->iid = (char*) malloc(strlen(value) + 1);
		if (p->iid != NULL) {
			strcpy(p->iid, value);
			return 1;
		}
	}

	return 0;
}

int individual_set_mat(struct individual *p, const char *value) {
	if (p != NULL && value != NULL) {
		if (p->mat != NULL) {
			free(p->mat);
			p->mat = NULL;
		}
		
		p->mat = (char*) malloc(strlen(value) + 1);
		if (p->mat != NULL) {
			strcpy(p->mat, value);
			return 1;
		}
	}

	return 0;
}

int individual_set_pat(struct individual *p, const char *value) {
	if (p != NULL && value != NULL) {
		if (p->pat != NULL) {
			free(p->pat);
			p->pat = NULL;
		}
		
		p->pat = (char*) malloc(strlen(value) + 1);
		if (p->pat != NULL) {
			strcpy(p->pat, value);
			return 1;
		}
	}

	return 0;
}

int individual_set_sexcode(struct individual *p, const char* value) {
	if (p != NULL && value != NULL) {
		if (p->sexcode != NULL) {
			free(p->sexcode);
			p->sexcode = NULL;
		}
		
		p->sexcode = (char*) malloc(strlen(value) + 1);
		if (p->sexcode != NULL) {
			strcpy(p->sexcode, value);
			return 1;
		}
	}

	return 0;
}

int individual_insert_one(struct individual *c, BOOL value) 
{
	if (c != NULL && (value == TRUE || value == FALSE)) {	
		if (c->nOne == 0) {
			c->one = (BOOL*) malloc(sizeof(BOOL));
			if (c->one != NULL) {
				c->one[c->nOne] = value;
				c->nOne++;

				return 1;
			}
		} else if (c->nOne >  0) {
			BOOL *pNew = NULL, *pOld = NULL;

			pOld = c->one;
			pNew = (BOOL*) realloc(c->one, ((sizeof(BOOL) * c->nOne) + sizeof(BOOL)));
			if (pNew != NULL) {
				c->one = pNew;
				c->one[c->nOne] = value;
				c->nOne++;

				return 1;
			} else {
				c->one = pOld;
				return 0;
			}
		}
	}

	return 0;
}

int individual_insert_two(struct individual *c, BOOL value) 
{
	if (c != NULL && (value == TRUE || value == FALSE)) {	
		if (c->nTwo == 0) {
			c->two = (BOOL*) malloc(sizeof(BOOL));
			if (c->two != NULL) {
				c->two[c->nTwo] = value;
				c->nTwo++;

				return 1;
			}
		} else if (c->nTwo >  0) {
			BOOL *pNew = NULL, *pOld = NULL;

			pOld = c->two;
			pNew = (BOOL*) realloc(c->two, ((sizeof(BOOL) * c->nTwo) + sizeof(BOOL)));
			if (pNew != NULL) {
				c->two = pNew;
				c->two[c->nTwo] = value;
				c->nTwo++;

				return 1;
			} else {
				c->two = pOld;
				return 0;
			}
		}
	}

	return 0;
}

int individual_alloc_one(struct individual *p, int size) {
	if (p != NULL) {
		if (p->one != NULL) {
			free(p->one);
			p->one = NULL;
			p->nOne = 0;
		}
		p->one = (BOOL*) malloc(sizeof(BOOL) * size);
		if (p->one != NULL) {
			p->nOne = size;
			return 1;
		} else {
			return 0;
		}
	}

	return 0;
}

int individual_alloc_two(struct individual *p, int size) {
	if (p != NULL) {
		if (p->two != NULL) {
			free(p->two);
			p->two = NULL;
			p->nTwo = 0;
		}
		p->two = (BOOL*) malloc(sizeof(BOOL) * size);
		if (p->two != NULL) {
			p->nTwo = size;
			return 1;
		} else {
			return 0;
		}
	}

	return 0;
}
